////////////////////////////////////////////////////////////////////////////////
//
//	Original file Name: SoundManager.java
//	Originating Author: JWhitefield
//	
//	Description: Manages the sound assets within the application 
//
////////////////////////////////////////////////////////////////////////////////

package com.jjw.game.sound;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Manages the sound assets within the application 
 * 
 * @author JWhitefield
 *
 */
public class SoundManager {

	//--------------------------------------------------------------------------
	//
	//Properties
	//
	//--------------------------------------------------------------------------
		
	//----------------------------------
	// Public
	//----------------------------------
	
	/**
	 * Static reference to the sound assets directory 
	 */
	static final String ASSET_SOUND_DIRECTORY = "assets/sound/";
	
	/**
	 * Default volume for sounds 
	 */
	static double DEFAULT_VOLUME = 1;
	
	//----------------------------------
	//  Getters / Setters
	//----------------------------------
	
	//----------------------------------
	// Private
	//----------------------------------
	
	/**
	 * Singleton object for the sound manager 
	 */
	private static SoundManager instance;	
	
	/**
	 * List of sounds which have been loaded into the application 
	 */
	private HashMap<String, Sound> loadedSoundAssets;

	/**
	 * List of the created playlist's
	 */
	private List<Playlist> regiesteredPlaylists;
	
	/**
	 * List of all sound asset references in the application
	 */
	private static final String[] soundAssets = { Sound.BACKGROUND_AMBIANT, Sound.BACKGROUND_PIANO, Sound.EFFECT_SWORD_SWING };
	
	//--------------------------------------------------------------------------
	//
	//  Methods
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	// Public
	//----------------------------------
	
	/**
	 * Hide constructor so that classes outside of this one cannot create an instance of it 
	 */
	SoundManager() {
		
		//Create a new list for the play list's
		this.regiesteredPlaylists = new ArrayList<Playlist>();
		
		//Load the sound manager 
		this.loadSoundManager();
	}
	
	/**
	 * Get and instance of the sound manager 
	 * 
	 * @return	return that instance 
	 */
	public static SoundManager getInstance() {
		
		//If we don't have an instance of it 
		if( instance == null ) {
			instance = new SoundManager();
		}
		
		//Return the instance of the sound manager 
		return instance;
	}
	
	/**
	 * Play the sound with this reference
	 * 
	 * @param soundReference the static reference from the sound in the sound class
	 */
	public void playSound( String soundReference ) {
		
		//Get the sound asset 
		Sound sound = this.getSoundByReference( soundReference );
		
		//If we found the sound try and play it
		if( sound != null )
			sound.play();
	}

	/**
	 * Pause the sound with this reference
	 * 
	 * @param soundReference the static reference from the sound in the sound class
	 */
	public void pauseSound( String soundReference ) {
		
		//Get the sound asset 
		Sound sound = this.getSoundByReference( soundReference );
		
		//If we found the sound try and pause it
		if( sound != null )
			sound.pause();
	}

	/**
	 * Resume the sound with this reference
	 * 
	 * @param soundReference the static reference from the sound in the sound class
	 */
	public void resumeSound( String soundReference ) {
		
		//Get the sound asset 
		Sound sound = this.getSoundByReference( soundReference );
		
		//If we found the sound try and pause it
		if( sound != null )
			sound.resume();
	}
	
	/**
	 * Stop the sound with this reference
	 * 
	 * @param soundReference the static reference from the sound in the sound class
	 */
	public void stopSound( String soundReference ) {
		
		//Get the sound asset 
		Sound sound = this.getSoundByReference( soundReference );
		
		//If we found the sound try and stop it
		if( sound != null )
			sound.stop();
	}
	
	/**
	 * Pauses all currently playing sounds  
	 */
	public void pauseAllSounds() {
		
		//Loop through all the sound assets pausing them if needed 
		for (Map.Entry<String, Sound> soundAsset : this.loadedSoundAssets.entrySet()) {
			
			//Pause the sound asset 
			soundAsset.getValue().pause();
		}
	}
	
	/**
	 * Resumes all currently paused sounds  
	 */
	public void resumeAllSounds() {
		
		//Loop through all the sound assets resuming them if needed 
		for (Map.Entry<String, Sound> soundAsset : this.loadedSoundAssets.entrySet()) {
			
			//Resume the sound asset 
			soundAsset.getValue().resume();
		}
	}
	
	/**
	 * Stops all currently playing sounds  
	 */
	public void stopAllSounds() {
		
		//Loop through all the sound assets stopping them if needed 
		for (Map.Entry<String, Sound> soundAsset : this.loadedSoundAssets.entrySet()) {
			
			//Stop the sound asset 
			soundAsset.getValue().stop();
		}
	}
	
	/**
	 * Sets the volume for the sounds 
	 * 
	 * @param
	 */
	public void setVolume( double volume ) {
		
		//Normalise the volume passed in
		DEFAULT_VOLUME = Math.max(0, Math.min(volume, 1));
		
		//Loop through all the sound assets setting their volumes 
		for (Map.Entry<String, Sound> soundAsset : this.loadedSoundAssets.entrySet()) {
			
			//Set the volume to the default volume
			soundAsset.getValue().setVolume(DEFAULT_VOLUME);
		}
	}
	
	/**
	 * Creates a play list of the sounds passed in 
	 * 
	 * Looping is defaulted to false
	 * 
	 * @param soundReferences	references to the sounds in the play list
	 * @return					a play list object which can start and stop the sounds
	 */
	public Playlist createPlaylist( String[] soundReferences ) {
		
		//Calls the other create play list function with a false loop
		return this.createPlaylist(soundReferences, false);
	}
	
	/**
	 * Creates a play list of the sounds passed in 
	 * 
	 * @param soundReferences	references to the sounds in the play list
	 * @param loopPlaylist 		weather the play list will automatically loop 
	 * @return					a play list object which can start and stop the sounds
	 */
	public Playlist createPlaylist( String[] soundReferences, boolean loopPlaylist) {
		
		//Play list we are creating place holder 
		Playlist createdPlaylist = null;
		
		//If the references list is null return the null play list
		if( soundReferences == null )
			return createdPlaylist;
		
		//Place holder for the sound 
		Sound sound = null;
		
		//Creates a new list of play list sounds
		Sound[] playlistSounds = new Sound[ soundReferences.length ];
		
		//Loop through the sound references
		for( int i = 0; i < soundReferences.length; i++ )
		{
			//Get the sound asset
			sound = new Sound( soundReferences[i] );
			
			//Add the sound onto the list
			playlistSounds[i] = sound; 
		}
		
		//Create new play list with the array of sounds we created 
		createdPlaylist = new Playlist( playlistSounds, loopPlaylist );
		
		//Keep a record of this play list
		this.regiesteredPlaylists.add(createdPlaylist);
		
		//Return the created play list 
		return createdPlaylist;
	}
	
	//----------------------------------
	// Private
	//----------------------------------
	
	/**
	 * Loads the sound manager and all the related sound clips
	 */
	private void loadSoundManager() {
		
		//Create a new loaded assets list 
		this.loadedSoundAssets = new HashMap<String, Sound>();
			
		//Sound asset place holder
		Sound soundAsset = null;
		
		//Loop through all asset references, creating them as sounds 
		for (int i = 0; i < SoundManager.soundAssets.length; i++) {
			
			//Get the asset reference
			String soundAssetReference = SoundManager.soundAssets[i];
			
			//Create a new sound asset
			soundAsset = new Sound( soundAssetReference );
			
			//Add this sound to the sound list 
			this.loadedSoundAssets.put(soundAssetReference, soundAsset);
		}
	}
	
	/**
	 * Gets a sound asset by the reference 
	 * 
	 * @param soundReference 	the reference to the sound asset
	 * @return 					the sound with this reference 
	 */
	private Sound getSoundByReference( String soundReference ) {
		
		//If the loaded asset list is null stop here
		if( this.loadedSoundAssets == null )
			return null;
		
		//Return the item with this reference
		return this.loadedSoundAssets.get( soundReference );
	}
	
	//----------------------------------
	// Overridden / Implemented
	//----------------------------------
	
}
